
#include "SecurityChain.h"

/** Constructor for the security chain. */
SecurityChain::SecurityChain()
{
}

/** Destructor for the security chain (and all the subunits under the
 * control of the chain). */
SecurityChain::~SecurityChain()
{
   for (int i = 0; i < secuchain.size(); i++)
      delete secuchain.at(i);
}

/** Adds a security token which was allocated with a new to the
 * security chain. Responsibility for the corresponding delete now
 * lies with this object. The security tokens will be queried for
 * authentication in order of being added (while respecting the
 * authentication type demands of the server). */
void SecurityChain::addSecurityToken(SecurityToken *sectoken)
{
   secuchain.push_back(sectoken);
}

/** Is the chain exhausted of methods of authentication?
 * 
 * @return Zero if there are still authentications for the client to
 * try, non-zero if there are no authentications remaining. */
int SecurityChain::isExhausted()
{
   int someremaining = 1;
   for (int i = 0; i < secuchain.size(); i++)
      someremaining &= secuchain.at(i)->wasTried();
   if (secuchain.size() == 0)
      someremaining = 0;
   return (someremaining == 0);
}

/** Get the next token that is capable of authenticating using a key.
 * 
 * @return A token that uses key-based authentication, or NULL if one
 * does not exist. */
SecurityToken *SecurityChain::getNextKeyToken()
{
   for (int i = 0; i < secuchain.size(); i++)
      if ((secuchain.at(i)->getAuthenticationType() == SecurityToken::SSH_AUTH_TYPE_KEY) &&
          (secuchain.at(i)->wasTried() == 0))
         return secuchain.at(i);
}

/** Get the next token that is capable of authenticating
 * interactively.
 * 
 * @return A token that uses interactive authentication, or NULL if
 * one does not exist. */
SecurityToken *SecurityChain::getNextInteractiveToken()
{
   for (int i = 0; i < secuchain.size(); i++)
      if ((secuchain.at(i)->getAuthenticationType() == SecurityToken::SSH_AUTH_TYPE_INTERACTIVE) &&
          (secuchain.at(i)->wasTried() == 0))
         return secuchain.at(i);
}

/** Get the next token that is capable of authenticating ith a
 * password.
 * 
 * @return A token that uses password authentication, or NULL if one
 * does not exist. */
SecurityToken *SecurityChain::getNextPasswordToken()
{
   for (int i = 0; i < secuchain.size(); i++)
      if ((secuchain.at(i)->getAuthenticationType() == SecurityToken::SSH_AUTH_TYPE_PASSWORD) &&
          (secuchain.at(i)->wasTried() == 0))
         return secuchain.at(i);
}
